package cn.bouncyslime.graduationProject.nba.crawler.spider;

import cn.bouncyslime.graduationProject.nba.dto.*;
import cn.bouncyslime.graduationProject.nba.util.BigDecimalUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import us.codecraft.webmagic.Page;
import us.codecraft.webmagic.Site;
import us.codecraft.webmagic.Spider;
import us.codecraft.webmagic.pipeline.ConsolePipeline;
import us.codecraft.webmagic.processor.PageProcessor;
import us.codecraft.webmagic.selector.Html;
import us.codecraft.webmagic.selector.Selectable;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

/**
 * @author 张一卓
 * @date 2020/4/2 23:44
 **/
public class PS_PlayerDataPageProcessor implements PageProcessor {

    private static final Logger logger = LoggerFactory.getLogger(PS_PlayerDataPageProcessor.class);

    private Site site = Site.me().setSleepTime(1500).setRetryTimes(3).setRetrySleepTime(1000).setCharset("utf-8")
            .setUserAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.369")
            .addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
            .addHeader("Connection", "keep-alive")
            .addHeader("Host", "www.stat-nba.com")
            .addCookie("__cfduid", "def62db9852e6b626f3d744bacadd235a1585654597")
            .addCookie("Hm_lvt_102e5c22af038a553a8610096bcc8bd4", "1585654597")
            .addCookie("yjs_id", "aHR0cHM6Ly93d3cuYmFpZHUuY29tL2xpbms/dXJsPXlGVU92Y0NMMERvR3ZUT01SVm1kS05NeExSeDNEWHFxcklfakxDSXVpMHJxY1E0RkJITTFncEhGX2lQcHJ2ekgmd2Q9JmVxaWQ9ZGM3OTgyN2YwMDczMjg1OTAwMDAwMDAzNWU4MzJiNDN8MTU4NTY1NDU5Njg0Ng")
            .addCookie("ctrl_time", "1")
            .addCookie("Hm_lpvt_102e5c22af038a553a8610096bcc8bd4", "1585672286");

    @Override
    public void process(Page page) {
        String pageUrl = page.getUrl().toString();
        if (page.isDownloadSuccess()) {
            logger.info(">>>> 开始爬取球员数据，url = " + pageUrl);
            logger.info(">> 以下为平均数据");
            crawlAveragingData(page);
            logger.info(">> 以下为总计数据");
            crawlSummaryData(page);
            logger.info(">> 以下为单场最高数据");
            crawlSingleData(page);
            logger.info(">> 以下为进阶 基础 数据");
            crawlAdvancedBasicData(page);
            logger.info(">> 以下为进阶 投篮 数据");
            crawlAdvancedShootingData(page);
        } else {
            logger.warn(">> " + pageUrl + "页面爬取失败");
        }
    }

    @Override
    public Site getSite() {
        return site;
    }

    private void crawlAveragingData(Page page) {
        Html html = page.getHtml();
        Selectable averageSelectable = html.xpath("//table[@class='stat_box][@id='stat_box_avg']");
        if (!averageSelectable.match()) {
            return;
        }
        List<Selectable> rowSelectable = averageSelectable.xpath("tbody/tr[@class='sort']").nodes();
        List<PS_PlayerAveragingDto> resultList = new ArrayList<>();
        for (Selectable selectable : rowSelectable) {
            PS_PlayerAveragingDto playerAveragingDto = new PS_PlayerAveragingDto();
            playerAveragingDto.setPlayerId((Integer) page.getRequest().getExtra("playerId"));
            List<String> row = selectable.xpath("td/allText()").all();
            if (row.get(2).contains("总计")) {
                continue;
            } else {
                String cell;
                for (int i = 1; i < row.size(); i++) {
                    cell = row.get(i);
                    if (cell != null && !"".equals(cell.trim())) {
                        switch (i) {
                            case 1:
                                playerAveragingDto.setSeason(cell.replace(" ", ""));
                                break;
                            case 2:
                                playerAveragingDto.setTeamCName(cell.replace(" ", ""));
                                break;
                            case 3:
                                playerAveragingDto.setAppearances(Integer.valueOf(cell));
                                break;
//                            case 4:
//                                playerAveragingDto.setStarting(Integer.valueOf(cell));
//                                break;
                            case 4:
                                playerAveragingDto.setPlayingTime(new BigDecimal(cell));
                                break;
                            case 5:
                                playerAveragingDto.setShootingPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 6:
                                playerAveragingDto.setShootingAmount(new BigDecimal(cell));
                                break;
                            case 7:
                                playerAveragingDto.setAttempts(new BigDecimal(cell));
                                break;
                            case 8:
                                playerAveragingDto.setThreePointPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 9:
                                playerAveragingDto.setThreePointAmount(new BigDecimal(cell));
                                break;
                            case 10:
                                playerAveragingDto.setThreePointAttempts(new BigDecimal(cell));
                                break;
                            case 11:
                                playerAveragingDto.setPenaltyKickPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 12:
                                playerAveragingDto.setPenaltyKickAmount(new BigDecimal(cell));
                                break;
                            case 13:
                                playerAveragingDto.setPenaltyKickAttempts(new BigDecimal(cell));
                                break;
                            case 14:
                                playerAveragingDto.setRebound(new BigDecimal(cell));
                                break;
                            case 15:
                                playerAveragingDto.setFrontRebound(new BigDecimal(cell));
                                break;
                            case 16:
                                playerAveragingDto.setBackRebound(new BigDecimal(cell));
                                break;
                            case 17:
                                playerAveragingDto.setAssists(new BigDecimal(cell));
                                break;
                            case 18:
                                playerAveragingDto.setSteal(new BigDecimal(cell));
                                break;
                            case 19:
                                playerAveragingDto.setBlockShot(new BigDecimal(cell));
                                break;
                            case 20:
                                playerAveragingDto.setFault(new BigDecimal(cell));
                                break;
                            case 21:
                                playerAveragingDto.setFoul(new BigDecimal(cell));
                                break;
                            case 22:
                                playerAveragingDto.setScore(new BigDecimal(cell));
                                break;
                            case 23:
                                playerAveragingDto.setWins(Integer.parseInt(cell));
                                break;
                            case 24:
                                playerAveragingDto.setLosses(Integer.parseInt(cell));
                                break;
                        }
                    }
                }
//                logger.debug(playerAveragingDto.toString());
                resultList.add(playerAveragingDto);
            }
//            logger.debug(row.toString() + " >> size " + row.size());
        }
        page.putField("PS_playerAveragingDataList", resultList);
    }

    private void crawlSummaryData(Page page) {
        Html html = page.getHtml();
        Selectable summarySelectable = html.xpath("//table[@class='stat_box][@id='stat_box_tot']");
        if (!summarySelectable.match()) {
            return;
        }
        List<Selectable> rowSelectable = summarySelectable.xpath("tbody/tr[@class='sort']").nodes();
        List<PS_PlayerSummaryDto> resultList = new ArrayList<>();
        for (Selectable selectable : rowSelectable) {
            PS_PlayerSummaryDto playerSummaryDto = new PS_PlayerSummaryDto();
            playerSummaryDto.setPlayerId((Integer) page.getRequest().getExtra("playerId"));
            List<String> row = selectable.xpath("td/allText()").all();
            if (row.get(2).contains("总计")) {
                continue;
            } else {
                String cell;
                for (int i = 1; i < row.size(); i++) {
                    cell = row.get(i);
                    if (cell != null && !"".equals(cell.trim())) {
                        switch (i) {
                            case 1:
                                playerSummaryDto.setSeason(cell.replace(" ", ""));
                                break;
                            case 2:
                                playerSummaryDto.setTeamCName(cell.replace(" ", ""));
                                break;
                            case 3:
                                playerSummaryDto.setAppearances(Integer.valueOf(cell));
                                break;
//                            case 4:
//                                playerSummaryDto.setStarting(Integer.valueOf(cell));
//                                break;
                            case 4:
                                playerSummaryDto.setPlayingTime(Integer.valueOf(cell));
                                break;
                            case 5:
                                playerSummaryDto.setShootingPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 6:
                                playerSummaryDto.setShootingAmount(Integer.valueOf(cell));
                                break;
                            case 7:
                                playerSummaryDto.setAttempts(Integer.valueOf(cell));
                                break;
                            case 8:
                                playerSummaryDto.setThreePointPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 9:
                                playerSummaryDto.setThreePointAmount(Integer.valueOf(cell));
                                break;
                            case 10:
                                playerSummaryDto.setThreePointAttempts(Integer.valueOf(cell));
                                break;
                            case 11:
                                playerSummaryDto.setPenaltyKickPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 12:
                                playerSummaryDto.setPenaltyKickAmount(Integer.valueOf(cell));
                                break;
                            case 13:
                                playerSummaryDto.setPenaltyKickAttempts(Integer.valueOf(cell));
                                break;
                            case 14:
                                playerSummaryDto.setRebound(Integer.valueOf(cell));
                                break;
                            case 15:
                                playerSummaryDto.setFrontRebound(Integer.valueOf(cell));
                                break;
                            case 16:
                                playerSummaryDto.setBackRebound(Integer.valueOf(cell));
                                break;
                            case 17:
                                playerSummaryDto.setAssists(Integer.valueOf(cell));
                                break;
                            case 18:
                                playerSummaryDto.setSteal(Integer.valueOf(cell));
                                break;
                            case 19:
                                playerSummaryDto.setBlockShot(Integer.valueOf(cell));
                                break;
                            case 20:
                                playerSummaryDto.setFault(Integer.valueOf(cell));
                                break;
                            case 21:
                                playerSummaryDto.setFoul(Integer.valueOf(cell));
                                break;
                            case 22:
                                playerSummaryDto.setScore(Integer.valueOf(cell));
                                break;
                            case 23:
                                playerSummaryDto.setWins(Integer.parseInt(cell));
                                break;
                            case 24:
                                playerSummaryDto.setLosses(Integer.parseInt(cell));
                                break;
                        }
                    }
                }
//                logger.debug(playerSummaryDto.toString());
                resultList.add(playerSummaryDto);
            }
//            logger.debug(row.toString() + " >> size " + row.size());
        }
        page.putField("PS_playerSummaryDataList", resultList);
    }

    private void crawlSingleData(Page page) {
        Html html = page.getHtml();
        Selectable singleSelectable = html.xpath("//table[@class='stat_box][@id='stat_box_single']");
        if (!singleSelectable.match()) {
            return;
        }
        List<Selectable> rowSelectable = singleSelectable.xpath("tbody/tr[@class='sort']").nodes();
        List<PlayerSingleTopmostDto> resultList = new ArrayList<>();
        for (Selectable selectable : rowSelectable) {
            PlayerSingleTopmostDto playerSingleDto = new PlayerSingleTopmostDto();
            playerSingleDto.setPlayerId((Integer) page.getRequest().getExtra("playerId"));
            List<String> row = selectable.xpath("td/allText()").all();
            if (row.get(2).contains("总计")) {
                continue;
            } else {
                String cell;
                for (int i = 1; i < row.size(); i++) {
                    cell = row.get(i);
                    if (cell != null && !"".equals(cell.trim())) {
                        switch (i) {
                            case 1:
                                playerSingleDto.setSeason(cell.replace(" ", ""));
                                break;
                            case 2:
                                playerSingleDto.setTeamCName(cell.replace(" ", ""));
                                break;
                            case 3:
                                playerSingleDto.setPlayingTime(Integer.valueOf(cell));
                                break;
                            case 4:
                                playerSingleDto.setShootingPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 5:
                                playerSingleDto.setShootingAmount(Integer.valueOf(cell));
                                break;
                            case 6:
                                playerSingleDto.setAttempts(Integer.valueOf(cell));
                                break;
                            case 7:
                                playerSingleDto.setThreePointPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 8:
                                playerSingleDto.setThreePointAmount(Integer.valueOf(cell));
                                break;
                            case 9:
                                playerSingleDto.setThreePointAttempts(Integer.valueOf(cell));
                                break;
                            case 10:
                                playerSingleDto.setPenaltyKickPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 11:
                                playerSingleDto.setPenaltyKickAmount(Integer.valueOf(cell));
                                break;
                            case 12:
                                playerSingleDto.setPenaltyKickAttempts(Integer.valueOf(cell));
                                break;
                            case 13:
                                playerSingleDto.setRebound(Integer.valueOf(cell));
                                break;
                            case 14:
                                playerSingleDto.setFrontRebound(Integer.valueOf(cell));
                                break;
                            case 15:
                                playerSingleDto.setBackRebound(Integer.valueOf(cell));
                                break;
                            case 16:
                                playerSingleDto.setAssists(Integer.valueOf(cell));
                                break;
                            case 17:
                                playerSingleDto.setSteal(Integer.valueOf(cell));
                                break;
                            case 18:
                                playerSingleDto.setBlockShot(Integer.valueOf(cell));
                                break;
                            case 19:
                                playerSingleDto.setFault(Integer.valueOf(cell));
                                break;
                            case 20:
                                playerSingleDto.setFoul(Integer.valueOf(cell));
                                break;
                            case 21:
                                playerSingleDto.setScore(Integer.valueOf(cell));
                                break;
                        }
                    }
                }
//                logger.debug(playerSingleDto.toString());
                resultList.add(playerSingleDto);
            }
//            logger.debug(row.toString() + " >> size " + row.size());
        }
        page.putField("PS_playerSingleDataList", resultList);
    }

    private void crawlAdvancedBasicData(Page page) {
        Html html = page.getHtml();
        Selectable basicAdvancedSelectable = html.xpath("//table[@class='stat_box][@id='stat_box_advanced_basic']");
        List<PlayerAdvancedBasicDto> resultList = new ArrayList<>();
        if (!basicAdvancedSelectable.match()) {
            return;
        }
        List<Selectable> rowSelectable = basicAdvancedSelectable.xpath("tbody/tr[@class='sort']").nodes();
        for (Selectable selectable : rowSelectable) {
            PlayerAdvancedBasicDto playerAdvancedBasicDto = new PlayerAdvancedBasicDto();
            playerAdvancedBasicDto.setPlayerId((Integer) page.getRequest().getExtra("playerId"));
            List<String> row = selectable.xpath("td/allText()").all();
            if (row.get(2).contains("总计")) {
                continue;
            } else {
                String cell;
                for (int i = 1; i < row.size(); i++) {
                    cell = row.get(i);
                    if (cell != null && !"".equals(cell.trim())) {
                        switch (i) {
                            case 1:
                                playerAdvancedBasicDto.setSeason(cell.replace(" ", ""));
                                break;
                            case 2:
                                playerAdvancedBasicDto.setTeamCName(cell.replace(" ", ""));
                                break;
                            case 3:
                                playerAdvancedBasicDto.setReboundRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 4:
                                playerAdvancedBasicDto.setAttackReboundRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 5:
                                playerAdvancedBasicDto.setDefendReboundRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 6:
                                playerAdvancedBasicDto.setAssistsRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 7:
                                playerAdvancedBasicDto.setStealRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 8:
                                playerAdvancedBasicDto.setBlockShotRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 9:
                                playerAdvancedBasicDto.setFaultRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 10:
                                playerAdvancedBasicDto.setUsageRate(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 11:
                                playerAdvancedBasicDto.setAttackEfficiency(Integer.valueOf(cell));
                                break;
                            case 12:
                                playerAdvancedBasicDto.setDefendEfficiency(Integer.valueOf(cell));
                                break;
                            case 13:
                                playerAdvancedBasicDto.setWinShare(new BigDecimal(cell));
                                break;
                            case 14:
                                playerAdvancedBasicDto.setAttackWinShare(new BigDecimal(cell));
                                break;
                            case 15:
                                playerAdvancedBasicDto.setDefendWinShare(new BigDecimal(cell));
                                break;
                            case 16:
                                playerAdvancedBasicDto.setPlayerEfficiencyRating(new BigDecimal(cell));
                                break;
                            case 17:
                                playerAdvancedBasicDto.setDunk(Integer.valueOf(cell));
                                break;
                            case 18:
                                playerAdvancedBasicDto.setAndOne(Integer.valueOf(cell));
                                break;
                        }
                    }
                }
//                logger.debug(playerAdvancedBasicDto.toString());
                resultList.add(playerAdvancedBasicDto);
            }
//            logger.debug(row.toString() + " >> size " + row.size());
        }
        page.putField("PS_playerAdvancedBasicDataList", resultList);
    }

    private void crawlAdvancedShootingData(Page page){
        Html html = page.getHtml();
        Selectable shootingAdvancedSelectable = html.xpath("//table[@class='stat_box][@id='stat_box_advanced_shooting']");
        List<PlayerAdvancedShootingDto> resultList = new ArrayList<>();
        if (!shootingAdvancedSelectable.match()) {
            return;
        }
        List<Selectable> rowSelectable = shootingAdvancedSelectable.xpath("tbody/tr[@class='sort']").nodes();
        for (Selectable selectable : rowSelectable) {
            PlayerAdvancedShootingDto playerAdvancedShootingDto = new PlayerAdvancedShootingDto();
            playerAdvancedShootingDto.setPlayerId((Integer) page.getRequest().getExtra("playerId"));
            List<String> row = selectable.xpath("td/allText()").all();
            if (row.get(2).contains("总计")) {
                continue;
            } else {
                String cell;
                for (int i = 1; i < row.size(); i++) {
                    cell = row.get(i);
                    if (cell != null && !"".equals(cell.trim())) {
                        switch (i) {
                            case 1:
                                playerAdvancedShootingDto.setSeason(cell.replace(" ", ""));
                                break;
                            case 2:
                                playerAdvancedShootingDto.setTeamCName(cell.replace(" ", ""));
                                break;
                            case 3:
                                playerAdvancedShootingDto.setDistance(new BigDecimal(cell));
                                break;
                            case 4:
                                playerAdvancedShootingDto.setBasketPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 5:
                                playerAdvancedShootingDto.setBasketAmount(new BigDecimal(cell));
                                break;
                            case 6:
                                playerAdvancedShootingDto.setBasketAttempts(new BigDecimal(cell));
                                break;
                            case 7:
                                playerAdvancedShootingDto.setBasketProportion(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 8:
                                playerAdvancedShootingDto.setCloseTwoPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 9:
                                playerAdvancedShootingDto.setCloseTwoAmount(new BigDecimal(cell));
                                break;
                            case 10:
                                playerAdvancedShootingDto.setCloseTwoAttempts(new BigDecimal(cell));
                                break;
                            case 11:
                                playerAdvancedShootingDto.setCloseTwoProportion(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 12:
                                playerAdvancedShootingDto.setMiddleTwoPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 13:
                                playerAdvancedShootingDto.setMiddleTwoAmount(new BigDecimal(cell));
                                break;
                            case 14:
                                playerAdvancedShootingDto.setMiddleTwoAttempts(new BigDecimal(cell));
                                break;
                            case 15:
                                playerAdvancedShootingDto.setMiddleTwoProportion(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 16:
                                playerAdvancedShootingDto.setLongTwoPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 17:
                                playerAdvancedShootingDto.setLongTwoAmount(new BigDecimal(cell));
                                break;
                            case 18:
                                playerAdvancedShootingDto.setLongTwoAttempts(new BigDecimal(cell));
                                break;
                            case 19:
                                playerAdvancedShootingDto.setLongTwoProportion(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 20:
                                playerAdvancedShootingDto.setTrueShootingPercentage(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                            case 21:
                                playerAdvancedShootingDto.setShootingEfficiency(BigDecimalUtil.div(cell.replace("%", ""), "100", 3));
                                break;
                        }
                    }
                }
//                logger.debug(playerAdvancedShootingDto.toString());
                resultList.add(playerAdvancedShootingDto);
            }
//            logger.debug(row.toString() + " >> size " + row.size());
        }
        page.putField("PS_playerAdvancedShootingDataList", resultList);
    }

    public static void main(String[] args) {
        Spider.create(new PS_PlayerDataPageProcessor()).addUrl("http://www.stat-nba.com/player/stat_box/526_playoff.html")
                .addPipeline(new ConsolePipeline())
                .thread(5).run();
    }
}
